package com.onlyxiahui.common.utils.base.lang.util.collection;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import com.onlyxiahui.common.utils.base.lang.util.collection.ListConvertUtil.Converter;
import com.onlyxiahui.common.utils.base.lang.util.collection.ListConvertUtil.GetKey;
import com.onlyxiahui.common.utils.base.lang.util.collection.ListConvertUtil.GetValue;
import com.onlyxiahui.common.utils.base.lang.util.collection.ListConvertUtil.ValueBack;

/**
 * Description <br>
 * Date 2021-05-02 17:52:45<br>
 * 
 * @author XiaHui [onlovexiahui@qq.com]<br>
 * @since 1.0.0
 */

public class ListMapUtil {

	public static <K, V> Map<K, V> listToMapByKey(
			List<V> list,
			GetKey<V, K> getKey) {
		int size = (null == list) ? 128 : list.size();
		Map<K, V> map = new HashMap<>(size);
		if (null != list) {
			for (V v : list) {
				K key = getKey.getKey(v);
				map.put(key, v);
			}
		}
		return map;
	}

	public static <K, V> Map<K, List<V>> listToMapListByKey(
			List<V> list,
			GetKey<V, K> getKey) {
		int size = (null == list) ? 128 : list.size();
		Map<K, List<V>> map = new HashMap<>(size);

		if (null != list) {
			for (V b : list) {
				K key = getKey.getKey(b);
				List<V> items = map.get(key);
				if (null == items) {
					items = new ArrayList<>();
					map.put(key, items);
				}
				items.add(b);
			}
		}
		return map;
	}

	public static <K, S, T> Map<K, T> listToMapConvertByKey(
			List<S> list,
			Converter<S, T> valueConvert,
			GetKey<T, K> getKey) {
		int size = (null == list) ? 128 : list.size();
		Map<K, T> map = new HashMap<>(size);
		ListConvertUtil.convertListBack(list, valueConvert, (items) -> {
			if (null != items) {
				for (T target : items) {
					K key = getKey.getKey(target);
					map.put(key, target);
				}
			}
		});
		return map;
	}

	public static <K, S, T> Map<K, List<T>> listToMapListConvertByKey(
			List<S> list,
			Converter<S, T> valueConvert,
			GetKey<T, K> getKey) {
		int size = (null == list) ? 128 : list.size();
		Map<K, List<T>> map = new HashMap<>(size);
		ListConvertUtil.convertListBack(list, valueConvert, (values) -> {
			for (T v : values) {
				K key = getKey.getKey(v);
				List<T> items = map.get(key);
				if (null == items) {
					items = new ArrayList<>();
					map.put(key, items);
				}
				items.add(v);
			}
		});
		return map;
	}

	public static <K, S, T> Map<K, T> listToMapConvertByKeys(
			List<S> list,
			Converter<S, K> keyConvert,
			GetValue<List<K>, List<T>> getValue,
			GetKey<T, K> getKey) {
		int size = (null == list) ? 128 : list.size();
		Map<K, T> map = new HashMap<>(size);
		ListConvertUtil.convertListBackByKeys(list, keyConvert, getValue, (items) -> {
			if (null != items) {
				for (T target : items) {
					K key = getKey.getKey(target);
					map.put(key, target);
				}
			}
		});
		return map;
	}

	/**********************************************/

	public static <K, V> void listToMapBackByKey(
			List<V> list,
			GetKey<V, K> getKey,
			ValueBack<Map<K, V>> back) {
		Map<K, V> map = listToMapByKey(list, getKey);
		back.back(map);
	}

	public static <K, V> void listToMapListBackByKey(
			List<V> list,
			GetKey<V, K> getKey,
			ValueBack<Map<K, List<V>>> back) {
		Map<K, List<V>> map = listToMapListByKey(list, getKey);
		back.back(map);
	}

	public static <K, S, T> void listToMapConvertBackByKey(
			List<S> list,
			Converter<S, T> valueConvert,
			GetKey<T, K> getKey,
			ValueBack<Map<K, T>> back) {
		Map<K, T> map = listToMapConvertByKey(list, valueConvert, getKey);
		back.back(map);
	}

	public static <K, S, T> void listToMapListConvertBackByKey(
			List<S> list,
			Converter<S, T> valueConvert,
			GetKey<T, K> getKey,
			ValueBack<Map<K, List<T>>> back) {
		Map<K, List<T>> map = listToMapListConvertByKey(list, valueConvert, getKey);
		back.back(map);
	}

	public static <K, V, T> void listToMapConvertBackByKeys(
			List<V> list,
			Converter<V, K> keyConvert,
			GetValue<List<K>, List<T>> getValue,
			GetKey<T, K> getKey,
			ValueBack<Map<K, T>> back) {
		Map<K, T> map = listToMapConvertByKeys(list, keyConvert, getValue, getKey);
		back.back(map);
	}
}
